﻿using System;
using System.Collections.Specialized;
using System.IO;
using System.Xml.Serialization;

namespace ExtractItAll.Core
{
  public abstract class AppSettings
  {
    #region Delegates

    public delegate void AppSettingsEventHander(object o, AppSettingsEventArgs e);

    #endregion

    protected AppSettings()
    {
      InitAppSettings();
    }

    protected AppSettings(string sPath)
    {
      InitAppSettings();
      Load(sPath);
    }

    public string MyPath { get; set; }

    public StringCollection MyLocations { get; set; }

    /// <summary>
    /// Declare Class Events
    /// </summary>
    public event AppSettingsEventHander SettingsEvent;

    private void InitAppSettings()
    {
      MyLocations = new StringCollection();
    }

    /// <summary>
    /// Returns True if Saved successfully, False otherwise.
    /// Raises Event that includes exception and reason if case of error
    /// </summary>
    /// <param name="thePath"></param>
    /// <returns></returns>
    public bool SaveAppSettings(string thePath)
    {
      try
      {
        XmlSerializer xs = new XmlSerializer(GetType());
        FileStream fs = new FileStream(thePath, FileMode.Create);
        xs.Serialize(fs, this);
        fs.Close();
      }
      catch (FileNotFoundException fex)
      {
        AppSettingsEventArgs e = new AppSettingsEventArgs(settingsEventReason.FileNotFound, fex);
        SettingsEvent(this, e);
        return false;
      }
      catch (Exception ex)
      {
        AppSettingsEventArgs e = new AppSettingsEventArgs(settingsEventReason.OtherException, ex);
        SettingsEvent(this, e);
        return false;
      }
      return true;
    }

    /// <summary>
    /// Returns new appSettings object if successfull, null appSettings otherwise
    /// Raises Event that includes exception and reason if case of error
    /// </summary>
    /// <param name="thePath"></param>
    /// <returns></returns>
    public AppSettings GetAppSettings(string thePath)
    {
      try
      {
        AppSettings appSet;
        XmlSerializer xs = new XmlSerializer(GetType());
        FileStream fs = new FileStream(thePath, FileMode.Open);
        appSet = (AppSettings)xs.Deserialize(fs);
        fs.Close();
        return appSet;
      }

      catch (FileNotFoundException fex)
      {
        AppSettingsEventArgs e = new AppSettingsEventArgs(settingsEventReason.OtherException, fex);
        SettingsEvent(this, e);
        return null;
        ;
      }
      catch (Exception ex)
      {
        AppSettingsEventArgs e = new AppSettingsEventArgs(settingsEventReason.OtherException, ex);
        SettingsEvent(this, e);
        return null;
      }
    }

    /// <summary>
    /// This function loads the settings file directly to "this" instance of appSettings
    /// instead of returning the appSettings Object
    /// Returns true on success, false otherwise
    /// Raises Event that includes exception and reason if case of error
    /// </summary>
    /// <param name="thePath"></param>
    /// <returns></returns>
    public bool Load(string thePath)
    {
      try
      {
        AppSettings appSet;
        XmlSerializer xs = new XmlSerializer(GetType());
        FileStream fs = new FileStream(thePath, FileMode.Open);
        appSet = (AppSettings)xs.Deserialize(fs);
        foreach (System.Reflection.PropertyInfo pi in GetType().GetProperties())
        {
          if (pi.CanWrite)
          {
            try
            {
              pi.SetValue(this, pi.GetValue(appSet, null), null);
            }
            catch (Exception ex)
            {
              pi.SetValue(this, null, null);
            }
          }
        }
        fs.Close();
      }

      catch (FileNotFoundException fex)
      {
        AppSettingsEventArgs e = new AppSettingsEventArgs(settingsEventReason.OtherException, fex);
        SettingsEvent(this, e);
        return false;
        ;
      }
      catch (Exception ex)
      {
        AppSettingsEventArgs e = new AppSettingsEventArgs(settingsEventReason.OtherException, ex);
        SettingsEvent(this, e);
        return false;
      }
      return true;
    }
  }

  public class AppSettingsEventArgs : EventArgs
  {
    private settingsEventReason _settingsEvent;

    /// <summary>
    /// Constructor
    /// </summary>
    /// <param name="reason"></param>
    /// <param name="objInfo"></param>
    public AppSettingsEventArgs(settingsEventReason reason, object objInfo)
    {
      _settingsEvent = reason;
      this.objInfo = objInfo;
    }

    /// <summary>
    /// Public Property(s) to return value(s)
    /// </summary>
    public object objInfo { get; private set; }

    public settingsEventReason EventReason
    {
      get { return _settingsEvent; }
    }
  }

  public enum settingsEventReason
  {
    FileNotFound = 1,
    // Add additional event reasons to enum here
    OtherException = 99
  }
}